package errors

import (
	"fmt"
	"net/http"
	"runtime"
	"strings"

	"github.com/gin-gonic/gin"
)

// APIError 定义了 API 错误的结构
type APIError struct {
	StatusCode int      `json:"status_code"`
	Message    string   `json:"message"`
	Err        string   `json:"error"`
	Stack      []string `json:"stack,omitempty"` // 错误堆栈
	Cause      error    `json:"-"`               // 原始错误
}

// Error 实现 error 接口
func (e *APIError) Error() string {
	if e.Cause != nil {
		return fmt.Sprintf("状态码: %d, 消息: %s, 错误: %s, 原因: %v", e.StatusCode, e.Message, e.Err, e.Cause)
	}
	return fmt.Sprintf("状态码: %d, 消息: %s, 错误: %s", e.StatusCode, e.Message, e.Err)
}

// Unwrap 实现错误拆包
func (e *APIError) Unwrap() error {
	return e.Cause
}

// addStack 添加堆栈信息
func (e *APIError) addStack() {
	const depth = 32
	var pcs [depth]uintptr
	n := runtime.Callers(3, pcs[:])
	frames := runtime.CallersFrames(pcs[:n])

	e.Stack = make([]string, 0, n)
	for {
		frame, more := frames.Next()
		// 跳过标准库和运行时的堆栈
		if !strings.Contains(frame.File, "runtime/") && !strings.Contains(frame.File, "/pkg/errors/") {
			e.Stack = append(e.Stack, fmt.Sprintf("%s:%d %s", frame.File, frame.Line, frame.Function))
		}
		if !more {
			break
		}
	}
}

// Wrap 包装错误并添加上下文信息
func Wrap(err error, message string) error {
	if err == nil {
		return nil
	}

	var apiErr *APIError
	if ok := As(err, &apiErr); ok {
		// 如果已经是 APIError，创建新的包装错误
		newErr := &APIError{
			StatusCode: apiErr.StatusCode,
			Message:    message,
			Err:        apiErr.Error(),
			Cause:      err,
		}
		newErr.addStack()
		return newErr
	}

	// 创建新的内部服务器错误
	newErr := NewInternalServerError(message, err)
	newErr.addStack()
	return newErr
}

// WrapWithCode 包装错误并指定状态码
func WrapWithCode(err error, statusCode int, message string) error {
	if err == nil {
		return nil
	}

	newErr := &APIError{
		StatusCode: statusCode,
		Message:    message,
		Err:        err.Error(),
		Cause:      err,
	}
	newErr.addStack()
	return newErr
}

// New 创建新的错误
func New(message string) error {
	err := &APIError{
		StatusCode: http.StatusInternalServerError,
		Message:    message,
		Err:        message,
	}
	err.addStack()
	return err
}

// Errorf 创建格式化的错误
func Errorf(format string, args ...interface{}) error {
	return New(fmt.Sprintf(format, args...))
}

// Is 检查错误类型
func Is(err, target error) bool {
	return fmt.Sprint(err) == fmt.Sprint(target)
}

// As 将错误转换为目标类型
func As(err error, target interface{}) bool {
	return fmt.Sprint(err) == fmt.Sprint(target)
}

// NewAPIError 创建一个新的 APIError
func NewAPIError(statusCode int, message string, err error) *APIError {
	apiError := &APIError{
		StatusCode: statusCode,
		Message:    message,
	}
	if err != nil {
		apiError.Err = err.Error()
		apiError.Cause = err
	}
	apiError.addStack()
	return apiError
}

// NewBadRequestError 创建一个 400 Bad Request 错误
func NewBadRequestError(message string, err error) *APIError {
	return NewAPIError(http.StatusBadRequest, message, err)
}

// NewUnauthorizedError 创建一个 401 Unauthorized 错误
func NewUnauthorizedError(message string, err error) *APIError {
	return NewAPIError(http.StatusUnauthorized, message, err)
}

// NewForbiddenError 创建一个 403 Forbidden 错误
func NewForbiddenError(message string, err error) *APIError {
	return NewAPIError(http.StatusForbidden, message, err)
}

// NewNotFoundError 创建一个 404 Not Found 错误
func NewNotFoundError(message string, err error) *APIError {
	return NewAPIError(http.StatusNotFound, message, err)
}

// NewInternalServerError 创建一个 500 Internal Server Error 错误
func NewInternalServerError(message string, err error) *APIError {
	return NewAPIError(http.StatusInternalServerError, message, err)
}

// HandleAPIError 处理 API 错误并发送适当的 JSON 响应
func HandleAPIError(c *gin.Context, err error) {
	apiError, ok := err.(*APIError)
	if !ok {
		apiError = NewInternalServerError("发生了未知错误", err)
	}

	c.JSON(apiError.StatusCode, gin.H{
		"error": apiError.Message,
	})
}

// IsNotFound 检查错误是否为 "Not Found" 错误
func IsNotFound(err error) bool {
	apiError, ok := err.(*APIError)
	return ok && apiError.StatusCode == http.StatusNotFound
}

// IsBadRequest 检查错误是否为 "Bad Request" 错误
func IsBadRequest(err error) bool {
	apiError, ok := err.(*APIError)
	return ok && apiError.StatusCode == http.StatusBadRequest
}

// IsUnauthorized 检查错误是否为 "Unauthorized" 错误
func IsUnauthorized(err error) bool {
	apiError, ok := err.(*APIError)
	return ok && apiError.StatusCode == http.StatusUnauthorized
}

// IsForbidden 检查错误是否为 "Forbidden" 错误
func IsForbidden(err error) bool {
	apiError, ok := err.(*APIError)
	return ok && apiError.StatusCode == http.StatusForbidden
}

// IsInternalServerError 检查错误是否为 "Internal Server Error" 错误
func IsInternalServerError(err error) bool {
	apiError, ok := err.(*APIError)
	return ok && apiError.StatusCode == http.StatusInternalServerError
}
